#include "CudaPerson.h"
using namespace std;


dCPUtoGPUPersonVec* home_cpu_to_gpu_device_vec = NULL;
hCPUtoGPUPersonVec* home_cpu_to_gpu_host_vec = NULL;
dCPUtoGPUPersonVec* worker_cpu_to_gpu_device_vec = NULL;
hCPUtoGPUPersonVec* worker_cpu_to_gpu_host_vec = NULL;

dGPUtoCPUPersonVec* home_gpu_to_cpu_device_vec = NULL;
hGPUtoCPUPersonVec* home_gpu_to_cpu_host_vec = NULL;
dGPUtoCPUPersonVec* worker_gpu_to_cpu_device_vec = NULL;
hGPUtoCPUPersonVec* worker_gpu_to_cpu_host_vec = NULL;


__global__ void CPUtoGPUPersonCopy(Person* target, CPUtoGPUPerson* source, int size){
	int idx = blockIdx.x * blockDim.x + threadIdx.x;
	if(idx >= size) return;

	Person& p = target[idx];
	CPUtoGPUPerson sp = source[idx];
	p.status = sp.status;
	p.iday = sp.iday;
	p.ibits = sp.ibits;
	p.vbits = sp.vbits;
	p.vday = sp.vday;
}

__global__ void GPUtoCPUPersonCopy(GPUtoCPUPerson* target, Person* source, int size){
	int idx = blockIdx.x * blockDim.x + threadIdx.x;
	if(idx >= size) return;

	Person p = source[idx];
	GPUtoCPUPerson& tp = target[idx];
	tp.status = p.status;
	tp.iday = p.iday;
	tp.ibits = p.ibits;
	tp.nInfectedTime = p.nInfectedTime;
}


void CopyFromCPUtoGPU(
	vector<Person>&  cpu_person, dPersonVec* gpu_person,
	hCPUtoGPUPersonVec* cpu_temp_person, dCPUtoGPUPersonVec* gpu_temp_person,int pos, int size){

	#pragma omp parallel for
	for(int i = 0; i < size; i++){
		(*cpu_temp_person)[i].CopyFromCPU(cpu_person[pos+i]);
	}
	cudaMemcpy(thrust::raw_pointer_cast(gpu_temp_person->data()),&((*cpu_temp_person)[0]),
		size*sizeof(CPUtoGPUPerson),cudaMemcpyHostToDevice);

	int numOfBlks = size / 1024; 
	if(numOfBlks == 0){ cout << "problem of tranfering memory from cpu to gpu" << endl; getchar();}
	CPUtoGPUPersonCopy<<<(numOfBlks+1),1024>>>(
		thrust::raw_pointer_cast(gpu_person->data()),
		thrust::raw_pointer_cast(gpu_temp_person->data()),size);

	cudaError error = cudaThreadSynchronize();
	if(error != cudaSuccess){
		cout << cudaGetErrorString(error) << endl;
		getchar();
	}

}

void CopyFromGPUtoCPU(
	vector<Person>&  cpu_person, dPersonVec* gpu_person,
	hGPUtoCPUPersonVec* cpu_temp_person, dGPUtoCPUPersonVec* gpu_temp_person,int pos, int size){
	
	int numOfBlks = size / 1024; 
	if(numOfBlks == 0){ cout << "problem of tranfering memory from gpu to cpu" << endl; getchar();}
	GPUtoCPUPersonCopy<<<(numOfBlks+1),1024>>>(
		thrust::raw_pointer_cast(gpu_temp_person->data()),
		thrust::raw_pointer_cast(gpu_person->data()),size);
	/*thrust::for_each(gpu_person->begin(),gpu_person->end(),
		GPUtoCPUPersonOp(thrust::raw_pointer_cast(gpu_temp_person->data())));*/
		
	cudaMemcpy(&((*cpu_temp_person)[0]),thrust::raw_pointer_cast(gpu_temp_person->data()),
		size*sizeof(GPUtoCPUPerson),cudaMemcpyDeviceToHost);
	
	#pragma omp parallel for
	for(int i = 0 ; i < size; i++){
		(*cpu_temp_person)[i].CopyToCPU(cpu_person[i]);	
	}
	
}